package com.service.impl;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import com.service.DyDeployBeansService;
import com.util.ApplicationContextUtil;
//@Service("deployBeansService")
public class DyDeployBeansServerImpl implements DyDeployBeansService{
	private static boolean excludeInner = true;
	private final static Logger _log = Logger.getLogger(DyDeployBeansServerImpl.class);
	@Resource
	private ApplicationContextUtil applicationContextUtil;
	
	public void regBeans(String packageName) {
		// TODO Auto-generated method stub
		DefaultListableBeanFactory beanFactory=applicationContextUtil.getBeanFactory();
		Set<Class<?>> classSet = new HashSet<Class<?>>();
		classSet.addAll(ScanPackageAllClasses(packageName, true));
		BeanDefinitionBuilder bean;
		String[] strArr;
        String beanName;
        String refBeanName;
        for (Class<?> clazz : classSet) {
            if (clazz.isInterface()) {
                continue;
            }
            try {
				bean = BeanDefinitionBuilder.genericBeanDefinition(Class.forName(clazz.getName())).setScope("prototype");
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				continue;
			}

            strArr = clazz.getName().split("\\.");
            beanName = strArr[strArr.length - 1];
            //将类别首字母转换成小写
            beanName = beanName.replaceAll(beanName.charAt(0) + "", (beanName.charAt(0) + "").toLowerCase());
            beanName = beanName.replaceAll("Impl", "");

            if (beanName.contains("Service")) {
                //添加serviceBean，service需要主人dao
                refBeanName = beanName.replaceAll("Service", "Dao");
                bean.addPropertyReference(refBeanName, refBeanName);
                beanFactory.registerBeanDefinition(beanName, bean.getRawBeanDefinition());
            } else {
                //注册基bean
                beanFactory.registerBeanDefinition(beanName, bean.getRawBeanDefinition());
            }
        }
	}
	
	private Set<Class<?>> ScanPackageAllClasses(String basePackage,final boolean b){
		Set<Class<?>> classes=new LinkedHashSet<Class<?>>();
		String packageName = basePackage;
		String package2Path = basePackage.replace('.', '/');
		Enumeration<URL> dirs;
		try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(package2Path);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                	_log.info("扫描file类型的class文件....");
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    doScanPackageClassesByFile(classes, packageName, filePath,b);
                } else if ("jar".equals(protocol)) {
                	_log.info("扫描jar文件中的类....");
                    doScanPackageClassesByJar( classes,packageName, url, b);
                }
            }
        } catch (IOException e) {
            _log.error("文件读取错误");
        }
        return classes;
	}
	private void doScanPackageClassesByJar( Set<Class<?>> classes,String basePackage, URL url, final boolean b){
		String packageName = basePackage;
        String package2Path = packageName.replace('.', '/');
        JarFile jar;
        try {
            jar = ((JarURLConnection) url.openConnection()).getJarFile();
            Enumeration<JarEntry> entries = jar.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String name = entry.getName();
                if (!name.startsWith(package2Path) || entry.isDirectory()) {
                    continue;
                }
                // 判断是否递归搜索子包
                if (!b&& name.lastIndexOf('/') != package2Path.length()) {
                    continue;
                }
                // 判断是否过滤 inner class
                if (excludeInner && name.indexOf('$') != -1) {
                	_log.info("exclude inner class with name:" + name);
                    continue;
                }
                String classSimpleName = name.substring(name.lastIndexOf('/') + 1);
                // 判定是否符合过滤条件
                if (filterClassName(classSimpleName)) {
                    String className = name.replace('/', '.');
                    className = className.substring(0, className.length() - 6);
                    try {
                        classes.add(Thread.currentThread().getContextClassLoader().loadClass(className));
                        _log.info("载入"+className);
                    } catch (ClassNotFoundException e) {
                    	_log.error(e);
                    }
                }
            }
        } catch (IOException e) {
            _log.error("文件读取错误");
        }
	}
	private void doScanPackageClassesByFile(Set<Class<?>> classes, String packageName, String packagePath, final boolean b){
		File dir = new File(packagePath);
        if (!dir.exists() || !dir.isDirectory()) {
           return;
        }
        File[] dirfiles = dir.listFiles(new FileFilter() {

            // 自定义文件过滤规则
            public boolean accept(File file) {
                if (file.isDirectory()) {
                    return b;
                }
                String filename = file.getName();
                if (excludeInner && filename.indexOf('$') != -1) {
                    _log.info( "exclude inner class with name:" + filename);
                    return false;
                }
                return filterClassName(filename);
            }
        });
        for (File file : dirfiles) {
            if (file.isDirectory()) {
            	doScanPackageClassesByFile(classes, packageName + "." + file.getName(), file.getAbsolutePath(), b);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                } catch (ClassNotFoundException e) {
                    _log.error(className+"  没有找到");
                }
            }
        }
	}
	private boolean filterClassName(String className) {
		boolean b=true;
        if (!className.endsWith(".class")) {
            b= false;
        }
        return b;
    }

}
